﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace DWLib
{
    /// <summary>
    /// The time object registers time and allows observers to retrieve the current time.
    /// </summary>
    internal class Time
    {
        /// <summary>
        /// Singleton of a Time instance.
        /// </summary>
        private static Time time = new Time();

        /// <summary>
        /// This list contains IUpdateable(s) that will receive a notify
        /// </summary>
        private List<IUpdatable> observer;
        private Timer timer;
        public DoubleDigit milliseconds;
        public DoubleDigit seconds;
        public DoubleDigit minutes;
        public DoubleDigit hours;

        /// <summary>
        /// check for paused
        /// </summary>
        private bool paused = false;

        private Time()
        {
            observer = new List<IUpdatable>();
            // timer delay 2 seconds, ticks 0.5 seconds
            timer = new Timer(callback, null, 2000, 500);

            milliseconds = new DoubleDigit(0, 1);
            seconds = new DoubleDigit(0, 59);
            minutes = new DoubleDigit(0, 59);
            hours = new DoubleDigit(0, 23);
        }

        /// <summary>
        /// get Time Instance (Singleton)
        /// </summary>
        /// <returns>time</returns>
        public static Time getInstance()
        {
            return time;
        }

        /// <summary>
        /// Execute tick and notify observer
        /// </summary>
        /// <param name="obj">null</param>
        private void callback(object obj)
        {
            if (milliseconds.increment())
            {
                if (!paused)
                {
                    if (seconds.increment())
                    {
                        if (minutes.increment())
                        {
                            hours.increment();
                        }
                    }
                }
            }
            notify();
        }

        /// <summary>
        /// Set wether the time has to be paused
        /// </summary>
        /// <param name="value">true = paused; false = continue</param>
        public void SetPaused(bool value)
        {
            paused = value;
        }

        /// <summary>
        /// (Observer pattern) Notify observers via update
        /// </summary>
        private void notify()
        {
            foreach (var obs in observer)
            {
                obs.update();
            }
        }

        /// <summary>
        /// Add an observer to the time object
        /// </summary>
        /// <param name="obj">observer</param>
        public void attach(IUpdatable obj)
        {
            observer.Add(obj);
        }

        /// <summary>
        /// Remove an observer from the time object
        /// </summary>
        /// <param name="obj">observer</param>
        public void detach(IUpdatable obj)
        {
            observer.Remove(obj);
        }
    }
}
